home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
listings
/
v_02_04
/
2n04008a
< prev
next >
Wrap
Text File
|
1991-02-09
|
6KB
|
193 lines
/*
* COM.C Copyright (C) 1990 by Mark R. Nelson
*
* This module contains a complete interface to a multiport RS-232 board.
* It is presently configured for the Stargate Plus 4 board.
*/
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <conio.h>
#include "com.h"
void interrupt far interrupt_service_routine( void );
static BOARD board;
/*
* This routine opens a multiport board up. It initializes the data
* structure associated with the board, mostly from parameters passed
* by the caller. It needs to make a DOS call with getvect to get
* the old interrupt vector for the board, then another call to
* setvect to connect our interrupt_service_routine to the vector.
*/
BOARD *board_open( unsigned int address, unsigned char int_number )
{
unsigned char temp_port;
board.status_address = address;
board.irq_mask = (char) 1 << (int_number % 8 );
board.int_number = int_number;
board.port_count = 0;
board.old_vector = getvect( int_number );
setvect( int_number, interrupt_service_routine );
/*
* These two lines instruct the 8259 interrupt controller to start
* accepting interrupts from the multiport board.
*/
temp_port = (char) inportb( 0x21 );
outportb( 0x21, ~board.irq_mask & temp_port );
/*
* Return a pointer to the structure.
*/
return( &board );
}
/*
* This routine is called to set up a data structure and open a port
* on a board that should have already been opened.
*/
PORT *port_open( BOARD *board, unsigned int address, unsigned char match )
{
PORT *port;
if ((port = malloc( sizeof( PORT ))) == NULL)
return( NULL );
port->head = 0;
port->tail = 0;
port->match = match;
port->address = address;
board->ports[ board->port_count++ ] = port;
return(port);
}
/*
* This routine sets up the transmission parameters for the UART. See
* the data sheet for details on what is going on here. Finally, it
* enables interrupts so the port can start receiving.
*/
void port_set( PORT *port, long speed, char parity, int data, int stopbits )
{
unsigned char temp_port;
/*
* First write the new baud rate to the UART.
*/
outportb( port->address + 3, 0x80 );
outportb( port->address, (char)(115200L / speed ) & 0xff );
outportb( port->address + 1, (char)(115200L / speed ) >> 8 );
/*
* Set up line control register.
*/
if ( parity== 'E' )
temp_port = 0x8; /* Set bit 3 on for even parity */
else if ( parity == 'O' )
temp_port = 0x18;
else
temp_port = 0;
if ( stopbits == 2 )
temp_port |= 0x4;
if ( data == 6 )
temp_port |= 0x1;
else if ( data == 7 )
temp_port |= 0x2;
else if ( data == 8 )
temp_port |= 0x3;
outportb( port->address + 3, temp_port );
/*
* Turn on OUT2, RTS & DTR. OUT2 is necessary on the PC for
* interrupts to take effect.
*/
outportb( port->address + 4, 0xb );
/*
* Then enable receiver interrupts.
*/
outportb( port->address + 1, 0x1 );
}
/*
* This routine closes a board by disabling interrupts for that line
* and restoring the old interrupt vector. It also closes any ports
* that were left open.
*/
void board_close( BOARD *board )
{
unsigned char temp_port;
unsigned int i;
for ( i = 0 ; i < board->port_count ; i++ )
port_close( board->ports[ i ] );
temp_port = (unsigned char) inportb( 0x21 );
outportb( 0x21, board->irq_mask | temp_port);
setvect( board->int_number, board->old_vector );
}
/*
* This routine closes a port. All this means is disabling receiver
* interrupts, then freeing up the structure. Note that this routine
* should probably not be called by the user, it should be left up
* to board_close() to close all the ports.
*/
void port_close( PORT *port )
{
outportb( port->address + 1, 0x0 );
free( port );
}
/*
* port_putc() is used to output a single character through the given
* port. This is done by just wainting for the transmit holding register
* to be empty, then writing the character to the UART.
*/
void port_putc( PORT *port, unsigned char c )
{
while( (inportb(port->address+5) & 0x20) == 0 )
;
outportb(port->address,c);
}
/*
* port_getc() checks to see if there are any characters in the port's
* input buffer. If there are, the oldest one is pulled out and
* returned, otherwise an error code is returned. Note that the code
* is simplified by having a byte index and a 256 byte buffer.
*/
int port_getc(PORT *port)
{
if ( port->head == port->tail )
return( -1 );
else
return( port->buffer[ port->tail++ ] );
}
/*
* The interrupt service routine has to read in the status register,
* then figure out which port(s) have characters to be read.
* The characters are read in, and stuffed into the buffers.
*/
void interrupt far interrupt_service_routine()
{
int i;
unsigned char status_reg;
PORT *port;
status_reg = (unsigned char) inportb( board.status_address );
for ( i = 0 ; i < board.port_count ; i++ )
{
if ( board.ports[i]->match & status_reg ) {
port=board.ports[ i ];
port->buffer[ port->head ] = (unsigned char) inportb(port->address);
if ((port->head + 1 ) != port->tail)
port->head++;
}
}
/*
* This line sends the EOI signal to the interrupt controller, letting it
* know that we are done.
*/
outportb(0x20,0x20);
}